Content Security Policy (CSP) とその他のフロントエンドセキュリティヘッダーに関する包括的ガイド。Webアプリケーションを攻撃から保護し、世界中のユーザーセキュリティを強化します。
フロントエンドセキュリティヘッダー:コンテンツセキュリティポリシー(CSP)をマスターする
今日のデジタル環境において、Webアプリケーションはますます複雑化・相互接続化しており、セキュリティ上の脅威から保護することが最も重要です。バックエンドのセキュリティが注目されがちですが、フロントエンドのセキュリティも同様に重要です。フロントエンドセキュリティヘッダーは最初の防衛線として機能し、ブラウザにどのように振る舞うべきかを指示し、さまざまな攻撃からユーザーを保護するメカニズムを提供します。これらのヘッダーの中でも、コンテンツセキュリティポリシー(CSP)は、広範囲のリスクを軽減するための強力なツールとして際立っています。
フロントエンドセキュリティヘッダーとは?
フロントエンドセキュリティヘッダーは、Webサーバーがブラウザに送信するHTTPレスポンスヘッダーです。これらのヘッダーには、ブラウザが受信したコンテンツをどのように処理すべきかの指示が含まれています。これにより、次のような一般的な攻撃を防ぐことができます:
- クロスサイトスクリプティング(XSS): 信頼されたウェブサイトに悪意のあるスクリプトを注入すること。
- クリックジャッキング: ユーザーを騙して、認識しているものとは異なるものをクリックさせること。
- 中間者攻撃: ユーザーとサーバー間の通信を傍受すること。
最も重要なフロントエンドセキュリティヘッダーには、以下のようなものがあります:
- コンテンツセキュリティポリシー(CSP): ブラウザがリソースを読み込むことを許可するソースを定義します。
- Strict-Transport-Security (HSTS): ウェブサイトとのすべての通信でHTTPSを使用するようブラウザに強制します。
- X-Frame-Options: ウェブサイトがiframeに埋め込まれるのを防ぎ、クリックジャッキング攻撃を軽減します。
- X-XSS-Protection: ブラウザに組み込まれたXSSフィルターを有効にします。(注意:多くの場合CSPに取って代わられていますが、依然として防御層を提供できます)。
- Referrer-Policy: リクエストと共に送信されるリファラー情報の量を制御します。
- Feature-Policy (現在はPermissions-Policy): 開発者がブラウザの機能やAPIを選択的に有効化・無効化できるようにします。
コンテンツセキュリティポリシー(CSP)の詳細解説
コンテンツセキュリティポリシー(CSP)は、特定のページに対してユーザーエージェントが読み込むことを許可するリソースを制御するHTTPレスポンスヘッダーです。これは承認されたコンテンツのソースをホワイトリスト化するもので、XSS攻撃のリスクを大幅に削減します。スクリプト、スタイルシート、画像、フォントなどのリソースを読み込むことができるオリジンを明示的に定義することにより、CSPは攻撃者があなたのウェブサイトに悪意のあるコードを注入するのをはるかに困難にします。
CSPの仕組み
CSPは、さまざまな種類のコンテンツに対して承認されたソースのリストをブラウザに提供することで機能します。ブラウザがCSPに違反するリソースに遭遇すると、そのリソースをブロックし、違反を報告します。このブロックメカニズムにより、攻撃者がHTMLに悪意のあるコードを注入できたとしても、その実行を防ぐことができます。
CSPディレクティブ
CSPディレクティブはCSPポリシーの中核をなす要素です。これらはさまざまな種類のリソースに対して許可されたソースを指定します。最も一般的に使用されるディレクティブには、以下のようなものがあります:
- default-src: すべてのリソースタイプのデフォルトソースを設定します。これは、より具体的な他のディレクティブが定義されていない場合に適用されるフォールバックディレクティブです。
- script-src: JavaScriptに許可されたソースを指定します。
- style-src: CSSスタイルシートに許可されたソースを指定します。
- img-src: 画像に許可されたソースを指定します。
- font-src: フォントに許可されたソースを指定します。
- media-src: オーディオおよびビデオに許可されたソースを指定します。
- object-src: Flashのようなプラグインに許可されたソースを指定します。(可能であればプラグインを許可しないのが最善です)。
- frame-src: フレーム(iframe)に許可されたソースを指定します。
- connect-src: ネットワークリクエスト(AJAX, WebSockets)に許可されたソースを指定します。
- base-uri:
<base>要素で使用できるURLを制限します。 - form-action: フォームを送信できるURLを制限します。
- frame-ancestors:
<frame>,<iframe>,<object>,<embed>, または<applet>を使用してページを埋め込むことができる有効な親を指定します。このディレクティブはクリックジャッキングに対する保護を提供します。 - upgrade-insecure-requests: サイトのすべての安全でないURL(HTTPで読み込まれる)を、安全なURL(HTTPSで読み込まれる)に置き換えられたかのように扱うようユーザーエージェントに指示します。このディレクティブは、HTTPからHTTPSへ移行中のウェブサイトを対象としています。
- report-uri: CSP違反に関するレポートをブラウザが送信する先のURLを指定します。`report-to` を優先するため非推奨です。
- report-to: `Report-To` ヘッダーで定義されたグループ名を指定します。これにより、複数のレポートエンドポイントを指定するなど、より詳細なレポート制御が可能になります。
CSPソース値
ソース値は、リソースの読み込みが許可されるオリジンを定義します。一般的なソース値には、以下のようなものがあります:
- *: あらゆるソースからのコンテンツを許可します(本番環境での使用は避けてください!)。
- 'self': 保護されたドキュメントと同じオリジン(スキーム、ホスト、ポート)からのコンテンツを許可します。
- 'none': いかなるソースからのコンテンツも許可しません。
- 'unsafe-inline': インラインのJavaScriptとCSSの使用を許可します(本番環境での使用は避けてください!)。
- 'unsafe-eval': 動的なコード評価(例:
eval(),Function())の使用を許可します(本番環境での使用は避けてください!)。 - 'strict-dynamic': マークアップ内に存在するスクリプトにノンスまたはハッシュを付与することで明示的に与えられた信頼が、その祖先によって読み込まれるすべてのスクリプトに伝播されることを指定します。
- 'unsafe-hashes': 特定のインラインイベントハンドラを許可します。これは複雑で利益が限定的なため、一般的に推奨されません。
- data:: data URL (例: 埋め込み画像) からのリソース読み込みを許可します。注意して使用してください。
- mediastream:: `mediastream:` URIをメディアソースとして使用することを許可します。
- blob:: `blob:` URIをメディアソースとして使用することを許可します。
- filesystem:: ファイルシステムからのリソース読み込みを許可します。
- https://example.com: 特定のドメインとポートからのコンテンツを許可します。
- *.example.com: example.comの任意のサブドメインからのコンテンツを許可します。
- nonce-{random-value}: 一致するnonce属性を持つスクリプトやスタイルを許可します。これには、リクエストごとにサーバーサイドでランダムなnonce値を生成する必要があります。
- sha256-{hash-value}: 一致するSHA256、SHA384、またはSHA512ハッシュを持つスクリプトやスタイルを許可します。
CSPモード:強制とレポート専用
CSPは2つのモードで展開できます:
- 強制モード: このモードでは、ブラウザはCSPに違反するリソースをブロックします。これは本番環境で推奨されるモードです。CSPは `Content-Security-Policy` ヘッダーを使用して送信されます。
- レポート専用モード: このモードでは、ブラウザはCSP違反を報告しますが、リソースはブロックしません。これはCSPを強制する前にテストおよび評価するのに役立ちます。CSPは `Content-Security-Policy-Report-Only` ヘッダーを使用して送信されます。
CSPの実装:ステップバイステップガイド
CSPの実装は難しく思えるかもしれませんが、体系的なアプローチに従うことで、Webアプリケーションを効果的に保護できます。
1. レポート専用ポリシーから始める
まず、レポート専用モードでCSPを展開することから始めます。これにより、ウェブサイトの機能を妨げることなく違反を監視できます。report-uri または report-to ディレクティブを設定して、違反レポートを指定のエンドポイントに送信します。
ヘッダー例 (レポート専用):
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
2. 違反レポートを分析する
違反レポートを注意深く分析して、どのリソースがなぜブロックされているのかを特定します。これは、ウェブサイトのリソース依存関係を理解し、潜在的なセキュリティ脆弱性を特定するのに役立ちます。
違反レポートは通常、設定された report-uri または report-to エンドポイントにJSONペイロードとして送信されます。これらのレポートには、ブロックされたURI、違反したディレクティブ、ドキュメントURIなどの違反に関する情報が含まれています。
3. CSPポリシーを洗練させる
違反レポートに基づいて、強力なセキュリティ体制を維持しつつ、正当なリソースを許可するようにCSPポリシーを洗練させます。ブロックされているリソースに特定のソース値を追加します。インラインスクリプトやスタイルには、'unsafe-inline' の使用を避けるためにノンスまたはハッシュを使用することを検討してください。
4. 強制モードに移行する
CSPポリシーが正当なリソースをブロックしていないと確信できたら、強制モードに移行します。これにより、残りの違反がブロックされ、XSS攻撃に対する堅牢なセキュリティ層が提供されます。
ヘッダー例 (強制):
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report
5. CSPポリシーを監視・維持する
CSPは一度設定すれば終わりという解決策ではありません。ウェブサイトが進化し、新たなセキュリティ脅威が出現するにつれて、CSPポリシーを継続的に監視し、更新することが不可欠です。定期的に違反レポートを確認し、必要に応じてポリシーを調整してください。
CSPの実用例
さまざまなシナリオに対応するCSPの実用例をいくつか見てみましょう:
例1:シンプルなウェブサイト向けの基本的なCSP
このCSPは、同一オリジンからのコンテンツと、あらゆるソースからの画像を許可します。
Content-Security-Policy: default-src 'self'; img-src *
例2:特定のスクリプトおよびスタイルソースを持つCSP
このCSPは、同一オリジンおよび特定のCDNからのスクリプト、そして同一オリジンおよびインラインスタイルを許可します。
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
例3:インラインスクリプトにノンスを使用するCSP
このCSPは、各インラインスクリプトに一意のノンスを要求します。
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-r4nd0mn0nc3'
HTML:
<script nonce="r4nd0mn0nc3">console.log('Hello, world!');</script>
重要: nonce値はリクエストごとにサーバーで動的に生成する必要があります。これにより、攻撃者がnonceを再利用するのを防ぎます。
例4:クリックジャッキングを防ぐためにframe-ancestorsを制限するCSP
このCSPは、ページが `https://example.com` 以外のドメインのiframeに埋め込まれるのを防ぎます。
Content-Security-Policy: frame-ancestors 'self' https://example.com
例5:'strict-dynamic'と'self'へのフォールバックを使用した、より制限的なCSP
このCSPは、`strict-dynamic`をサポートしていない古いブラウザもサポートしつつ、モダンブラウザでは`strict-dynamic`を活用します。また、違反を監視するための`report-uri`も含まれています。
Content-Security-Policy: default-src 'self'; script-src 'strict-dynamic' 'nonce-{random-nonce}' 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report
サーバーサイドで`{random-nonce}`を動的に生成されたnonce値に置き換えることを忘れないでください。
CSPとシングルページアプリケーション(SPA)
SPAにCSPを実装することは、これらのアプリケーションの動的な性質のため困難な場合があります。SPAはDOMを生成・操作するためにJavaScriptに大きく依存しているため、慎重に扱わないとCSP違反につながる可能性があります。
SPAにCSPを実装するためのヒントをいくつか紹介します:
'unsafe-inline'と'unsafe-eval'を避ける: これらのディレクティブはSPAでは可能な限り避けるべきです。これらはアプリケーションのセキュリティを大幅に弱めます。- ノンスまたはハッシュを使用する: インラインスクリプトやスタイルにはノンスまたはハッシュを使用します。これはSPAで推奨されるアプローチです。
- Trusted Typesを検討する: Trusted TypesはDOMベースのXSS脆弱性を防ぐのに役立つブラウザAPIです。CSPと組み合わせて使用することで、セキュリティをさらに強化できます。
- CSP互換のフレームワークを使用する: 一部のフロントエンドフレームワーク(特定の構成を持つReact、Angular、Vue.jsなど)は、CSPをより簡単に実装するための機能を提供しています。
その他の重要なフロントエンドセキュリティヘッダー
CSPはフロントエンドセキュリティの礎ですが、包括的な防御戦略を提供するためには他のヘッダーも重要な役割を果たします:
Strict-Transport-Security (HSTS)
Strict-Transport-Security (HSTS) ヘッダーは、ウェブサイトへの接続に常にHTTPSを使用するようブラウザに指示します。これにより、接続をHTTPにダウングレードしようとする中間者攻撃を防ぎます。
ヘッダー例:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-age: ブラウザがサイトにHTTPS経由でのみアクセスすることを記憶すべき期間(秒単位)を指定します。本番環境では31536000秒(1年)の値が推奨されます。includeSubDomains: HSTSポリシーがドメインのすべてのサブドメインに適用されることを示します。preload: ドメインをブラウザにプリロードされるHSTS有効ドメインのリストに含めることを許可します。これには、Googleが管理するHSTSプリロードリストにドメインを申請する必要があります。
X-Frame-Options
X-Frame-Options ヘッダーは、ウェブサイトがiframeに埋め込まれるかどうかを制御することにより、クリックジャッキング攻撃を防ぎます。
ヘッダー例:
X-Frame-Options: DENY
可能な値:
DENY: オリジンに関係なく、ページがiframeに表示されるのを防ぎます。SAMEORIGIN: iframeのオリジンがページのオリジンと一致する場合にのみ、ページがiframeに表示されるのを許可します。ALLOW-FROM uri: iframeのオリジンが指定されたURIと一致する場合にのみ、ページがiframeに表示されるのを許可します。注意:このオプションは非推奨であり、すべてのブラウザでサポートされているとは限りません。
注意: CSPの frame-ancestors ディレクティブは、フレーミングを制御するためのより柔軟で強力な方法を提供し、一般的に X-Frame-Options よりも優先されます。
X-XSS-Protection
X-XSS-Protection ヘッダーは、ブラウザに組み込まれたXSSフィルターを有効にします。CSPはXSS攻撃を防ぐためのより堅牢なソリューションですが、このヘッダーは、特にCSPを完全にはサポートしていない古いブラウザに対して、追加の防御層を提供できます。
ヘッダー例:
X-XSS-Protection: 1; mode=block
1: XSSフィルターを有効にします。0: XSSフィルターを無効にします。mode=block: XSS攻撃が検出された場合にページをブロックするようブラウザに指示します。report=uri: XSS攻撃が検出された場合にブラウザがレポートを送信する先のURLを指定します。
Referrer-Policy
Referrer-Policy ヘッダーは、リクエストと共に送信されるリファラー情報の量を制御します。リファラー情報はウェブサイトをまたいでユーザーを追跡するために使用される可能性があるため、これを制御することでユーザーのプライバシーを向上させることができます。
ヘッダー例:
Referrer-Policy: strict-origin-when-cross-origin
一般的な値のいくつか:
no-referrer: Refererヘッダーを送信しません。no-referrer-when-downgrade: TLS(HTTPS)のないオリジンにはRefererヘッダーを送信しません。origin: Refererヘッダーにオリジン(スキーム、ホスト、ポート)のみを送信します。origin-when-cross-origin: クロスオリジンリクエストにはオリジンを、同一オリジンリクエストには完全なURLを送信します。same-origin: 同一オリジンリクエストにはRefererヘッダーを送信しますが、クロスオリジンリクエストには送信しません。strict-origin: プロトコルのセキュリティレベルが同じ(HTTPSからHTTPS)場合にのみオリジンを送信し、より安全でない宛先(HTTPSからHTTP)にはヘッダーを送信しません。strict-origin-when-cross-origin: 同一オリジンリクエストを実行する際にオリジンを送信します。クロスオリジンリクエストの場合、プロトコルのセキュリティレベルが同じ(HTTPSからHTTPS)場合にのみオリジンを送信し、より安全でない宛先(HTTPSからHTTP)にはヘッダーを送信しません。unsafe-url: オリジンに関係なく、Refererヘッダーに完全なURLを送信します。機密情報が漏洩する可能性があるため、細心の注意を払って使用してください。
Permissions-Policy (旧Feature-Policy)
Permissions-Policy ヘッダー(旧称 Feature-Policy)は、開発者がブラウザの機能やAPIを選択的に有効化・無効化できるようにします。これにより、アプリケーションの攻撃対象領域を減らし、ユーザーのプライバシーを向上させることができます。
ヘッダー例:
Permissions-Policy: geolocation=()
この例では、ウェブサイトの地理位置情報APIを無効にしています。
Permissions-Policy で制御できるその他の機能には、以下のようなものがあります:
cameramicrophonegeolocationaccelerometergyroscopemagnetometerusbmidipaymentfullscreen
異なるプラットフォームでのセキュリティヘッダーの設定
セキュリティヘッダーの設定方法は、使用しているWebサーバーやプラットフォームによって異なります。以下に一般的な例をいくつか示します:
Apache
Apacheでは、.htaccess ファイルまたはサーバー設定ファイル(httpd.conf)に追加することでセキュリティヘッダーを設定できます。
.htaccess 設定例:
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report"
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header set X-Frame-Options "DENY"
Header set X-XSS-Protection "1; mode=block"
Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>
Nginx
Nginxでは、Nginx設定ファイル(nginx.conf)のserverブロックに追加することでセキュリティヘッダーを設定できます。
Nginx 設定例:
server {
listen 443 ssl;
server_name example.com;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; report-uri /csp-report";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
...
}
Node.js (Express)
Node.jsでは、Helmetのようなミドルウェアを使用してセキュリティヘッダーを設定できます。
Helmetを使用した例:
const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet());
// Customize CSP if needed
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://cdn.example.com"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:"],
reportUri: '/csp-report'
},
}));
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
Cloudflare
Cloudflareでは、ページルールまたは変換ルールを使用してセキュリティヘッダーを設定できます。
セキュリティヘッダーのテスト
セキュリティヘッダーを実装した後は、それらが正しく機能していることを確認するためにテストすることが重要です。ウェブサイトのセキュリティヘッダーを分析するのに役立ついくつかのオンラインツールがあります:
- SecurityHeaders.com: セキュリティヘッダーを分析するためのシンプルで効果的なツール。
- Mozilla Observatory: セキュリティヘッダーを含むウェブサイトのセキュリティをテストするための包括的なツール。
- WebPageTest.org: ウォーターフォールチャートでHTTPヘッダーを表示できます。
結論
フロントエンドセキュリティヘッダー、特にコンテンツセキュリティポリシー(CSP)は、Webアプリケーションをさまざまな攻撃から保護し、ユーザーのセキュリティを強化するために不可欠です。これらのヘッダーを慎重に実装および維持することにより、XSS、クリックジャッキング、その他のセキュリティ脆弱性のリスクを大幅に削減できます。レポート専用ポリシーから始め、違反レポートを分析し、ポリシーを洗練させ、その後強制モードに移行することを忘れないでください。ウェブサイトが進化し、新たな脅威が出現するにつれて、セキュリティヘッダーを定期的に監視・更新してください。
フロントエンドセキュリティに対して積極的なアプローチを採用することで、ユーザーとビジネスを保護する、より安全で信頼性の高いWebアプリケーションを構築できます。